﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Schema;
using XmlStudio.DataLayer;
using XmlStudio.Interfaces;

namespace XmlStudio.Models {


    /// <summary>
    /// Factory for creating elements for xsd schemas.
    /// </summary>
    internal static class XsdFactory {
        #region Fields
        private const string XsNamespaceUri = "http://www.w3.org/2001/XMLSchema";
        #endregion

        //#region Properties
        //public static string XsPrefix {
        //    get { return xsPrefix; }
        //    set { xsPrefix = value; }
        //}
        //#endregion

        #region All
        /// <summary>
        /// Creates element all. The all element specifies that the child elements can appear in any order and that each child element can occur zero or one time.
        /// </summary>
        /// <param name="model">Reference to xmlModel.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="maxOccurs">Optional. Specifies the maximum number of times the element can occur. The value must be 1.</param>
        /// <param name="minOccurs">Optional. Specifies the minimum number of times the element can occur. The value can be 0 or 1. Default value is 1.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementAll(IXsdModel model, string id, int? maxOccurs, int? minOccurs, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Group || parent == XsdElement.ComplexType || parent == XsdElement.Restriction || parent == XsdElement.Extension)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("all can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);

            if(maxOccurs.HasValue) {
                if(maxOccurs != 1) {
                    throw new ArgumentException("maxOccurs must be 1"); // TO DO: translate
                }

                AddXsdAttribute(attributes, "maxOccurs", maxOccurs.Value.ToString());
            }

            if(minOccurs.HasValue) {
                AddXsdAttribute(attributes, "minOccurs", minOccurs.Value.ToString());
            }

            AddAdditionalAttributes(attributes, additionalAttributes);
            return CreateElement(model, "all", attributes);
        }
        #endregion

        #region Annotation
        /// <summary>
        /// Creates element annotation. The annotation element is a top level element that specifies
        /// schema comments. The comments serve as inline documentation.
        /// </summary>
        /// <param name="model">Reference to xmlModel.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementAnnotation(IXsdModel model, string id, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            // parent can be any element

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);
            AddAdditionalAttributes(attributes, additionalAttributes);
            return CreateElement(model, "annotation", attributes);
        }
        #endregion

        #region Any
        /// <summary>
        /// Creates element any. The any element enables the author to extend the XML document with elements not specified by the schema.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="maxOccurs">Optional. Specifies the maximum number of times the any element can occur in the parent element.
        /// The value can be any number &gt;= 0, or if you want to set no limit on the maximum number, use the value "unbounded". Default value is 1.</param>
        /// <param name="minOccurs">Optional. Specifies the minimum number of times the any element can occur in the parent element. The value can be any number &gt;= 0. Default value is 1.</param>
        /// <param name="namespace">Optional. Specifies the namespaces containing the elements that can be used. Can be set to one of the following:
        /// * ##any - elements from any namespace is allowed (this is default)
        /// * ##other - elements from any namespace that is not the namespace of the parent element can be present
        /// * ##local - elements must come from no namespace
        /// * ##targetNamespace - elements from the namespace of the parent element can be present
        /// * List of {URI references of namespaces, ##targetNamespace, ##local} - elements from a space-delimited list of the namespaces can be present</param>
        /// <param name="processContents">Optional. Specifies how the XML processor should handle validation against the elements specified by this any element. Can be set to one of the following:
        /// * strict - the XML processor must obtain the schema for the required namespaces and validate the elements (this is default)
        /// * lax - same as strict but; if the schema cannot be obtained, no errors will occur
        /// * skip - The XML processor does not attempt to validate any elements from the specified namespaces</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementAny(IXsdModel model, string id, string maxOccurs, string minOccurs, string @namespace, ProcessContents? processContents,
            IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Choice || parent == XsdElement.Sequence)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("all can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);
            ParseMaxOccurs(maxOccurs, attributes);
            ParseMinOccurs(minOccurs, attributes);

            if(!string.IsNullOrEmpty(@namespace)) {
                AddXsdAttribute(attributes, "namespace", @namespace);
            }

            if(processContents.HasValue) {
                AddXsdAttribute(attributes, "processContents", processContents.ToString().ToLower());
            }

            AddAdditionalAttributes(attributes, additionalAttributes);
            return CreateElement(model, "any", attributes);
        }
        #endregion

        #region AnyAttribute
        /// <summary>
        /// Creates element anyAttribute. The anyAttribute element enables the author to extend the XML document with simpleTypes not specified by the schema.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="namespace">Optional. Specifies the namespaces containing the simpleTypes that can be used. Can be set to one of the following:
        /// * ##any - simpleTypes from any namespace is allowed (this is default)
        /// * ##other - simpleTypes from any namespace that is not the namespace of the parent element can be present
        /// * ##local - simpleTypes must come from no namespace
        /// * ##targetNamespace - simpleTypes from the namespace of the parent element can be present
        /// * List of {URI references of namespaces, ##targetNamespace, ##local} - simpleTypes from a space-delimited list of the namespaces can be present.</param>
        /// <param name="processContents">Optional. Specifies how the XML processor should handle validation against the elements specified by this any element. Can be set to one of the following:
        /// * strict - the XML processor must obtain the schema for the required namespaces and validate the elements (this is default)
        /// * lax - same as strict but; if the schema cannot be obtained, no errors will occur
        /// * skip - The XML processor does not attempt to validate any elements from the specified namespaces.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementAnyAttribute(IXsdModel model, string id, string @namespace, ProcessContents? processContents,
            IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.ComplexType || parent == XsdElement.Restriction || parent == XsdElement.Extension || parent == XsdElement.AttributeGroup)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("anyAttribute can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);
            if(!string.IsNullOrEmpty(@namespace)) {
                AddXsdAttribute(attributes, "namespace", @namespace);
            }

            if(processContents.HasValue) {
                AddXsdAttribute(attributes, "processContents", processContents.ToString().ToLower());
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "anyAttribute", attributes);
        }
        #endregion

        #region AppInfo
        /// <summary>
        /// Creates element appInfo. The appInfo element specifies information to be used by the application.
        /// This element must go within an annotation element.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="source">Optional. A URI reference that specifies the source of the application information.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementAppInfo(IXsdModel model, string source, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Annotation)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("appInfo can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            if(!string.IsNullOrEmpty(source)) {
                AddXsdAttribute(attributes, "source", source);
            }

            return CreateElement(model, "appInfo", attributes);
        }
        #endregion

        #region Attribute
        /// <summary>
        /// Creates element attribute. The attribute element defines an attribute.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="default">Optional. Specifies a default value for the attribute. Default and fixed simpleTypes cannot both be present.</param>
        /// <param name="fixed">Optional. Specifies a fixed value for the attribute. Default and fixed simpleTypes cannot both be present.</param>
        /// <param name="form">Optional. Specifies the form for the attribute. The default value is the value of the attributeFormDefault
        /// attribute of the element containing the attribute. Can be set to one of the following:
        /// * "qualified" - indicates that this attribute must be qualified with the namespace prefix and the no-colon-name (NCName) of the attribute
        /// * unqualified - indicates that this attribute is not required to be qualified with the namespace prefix and is matched against the (NCName) of the attribute</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Optional. Specifies the name of the attribute. Name and ref simpleTypes cannot both be present.</param>
        /// <param name="ref">Optional. Specifies a reference to a named attribute. Name and ref simpleTypes cannot both be present.
        /// If ref is present, simpleType element, form, and type cannot be present.</param>
        /// <param name="type">Optional. Specifies a built-in data type or a simple type. The type attribute can only be present when
        /// the content does not contain a simpleType element.</param>
        /// <param name="use">Optional. Specifies how the attribute is used. Can be one of the following values:
        /// * optional - the attribute is optional (this is default)
        /// * prohibited - the attribute cannot be used
        /// * required - the attribute is required</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementAttribute(IXsdModel model, string @default, string @fixed, Form? form, string id, string name,
            string @ref, string type, Use? use, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.AttributeGroup || parent == XsdElement.Schema || parent == XsdElement.ComplexType || parent == XsdElement.Restriction || parent == XsdElement.Extension)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("attribute can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            if(!string.IsNullOrEmpty(@default)) {
                AddXsdAttribute(attributes, "default", @default);
            }

            if(!string.IsNullOrEmpty(@fixed)) {
                AddXsdAttribute(attributes, "fixed", @fixed);
            }

            if(form.HasValue) {
                AddXsdAttribute(attributes, "form", form.Value.ToString().ToLower());
            }

            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(name)) {
                AddXsdAttribute(attributes, "name", name);
            }

            if(!string.IsNullOrEmpty(@ref)) {
                AddXsdAttribute(attributes, "ref", @ref);
            }

            if(!string.IsNullOrEmpty(type)) {
                AddXsdAttribute(attributes, "type", type);
            }

            if(use.HasValue) {
                AddXsdAttribute(attributes, "use", use.Value.ToString().ToLower());
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "attribute", attributes);
        }
        #endregion

        #region AttributeGroup
        /// <summary>
        /// Creates element attributeGroup. The attributeGroup element is used to group a set of attribute declarations
        /// so that they can be incorporated as a group into complex type definitions.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Optional. Specifies the name of the attribute group. Name and ref simpleTypes cannot both be present.</param>
        /// <param name="ref">Optional. Specifies a reference to a named attribute group. Name and ref simpleTypes cannot both be present.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementAttributeGroup(IXsdModel model, string id, string name, string @ref,
            IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.AttributeGroup || parent == XsdElement.ComplexType || parent == XsdElement.Schema || parent == XsdElement.Restriction || parent == XsdElement.Extension)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("attributeGroup can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(name)) {
                AddXsdAttribute(attributes, "name", name);
            }

            if(!string.IsNullOrEmpty(@ref)) {
                AddXsdAttribute(attributes, "ref", @ref);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "attributeGroup", attributes);
        }
        #endregion

        #region Choice
        /// <summary>
        /// Creates element choice. XML Schema choice element allows only one of the elements contained
        /// in the choice declaration to be present within the containing element.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="maxOccurs">Optional. Specifies the maximum number of times the choice element can occur in the parent element.
        /// The value can be any number &gt;= 0, or if you want to set no limit on the maximum number, use the value "unbounded". Default value is 1</param>
        /// <param name="minOccurs">Optional. Specifies the minimum number of times the choice element can occur in the parent the element.
        /// The value can be any number &gt;= 0. Default value is 1</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementChoice(IXsdModel model, string id, string maxOccurs, string minOccurs,
            IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Group || parent == XsdElement.Choice || parent == XsdElement.Sequence || parent == XsdElement.ComplexType || parent == XsdElement.Restriction
                || parent == XsdElement.Extension)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("choice can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            ParseMaxOccurs(maxOccurs, attributes);
            ParseMinOccurs(minOccurs, attributes);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "choice", attributes);
        }
        #endregion

        #region ComplexContent
        /// <summary>
        /// Creates element complexContent. The complexContent element defines extensions or restrictions on a complex type that contains mixed content or elements only.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="mixed">Optional. Specifies whether character data is allowed to appear between the child elements of this complexType element. Default is false.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementComplexContent(IXsdModel model, string id, bool? mixed, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.ComplexType)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("complexContent can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(mixed.HasValue) {
                AddXsdAttribute(attributes, "mixed", mixed.Value ? "true" : "false");
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "complexContent", attributes);
        }
        #endregion

        #region ComplexType
        /// <summary>
        /// Creates element complexType. The complexType element defines a complex type.
        /// A complex type element is an XML element that contains other elements and/or simpleTypes.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Optional. Specifies a name for the element.</param>
        /// <param name="abstract">Optional. Specifies whether the complex type can be used in an instance document. True indicates that an element cannot use this complex type directly but must use a complex type derived from this complex type. Default is false</param>
        /// <param name="mixed">Optional. Specifies whether character data is allowed to appear between the child elements of this complexType element. Default is false. If a simpleContent element is a child element, the mixed attribute is not allowed!</param>
        /// <param name="block">Optional. Prevents a complex type that has a specified type of derivation from being used in place of this complex type. This value can contain #all or a list that is a subset of extension or restriction:
        /// * extension - prevents complex types derived by extension
        /// * restriction - prevents complex types derived by restriction
        /// * #all - prevents all derived complex types</param>
        /// <param name="final">Optional. Prevents a specified type of derivation of this complex type element. Can contain #all or a list that is a subset of extension or restriction.
        /// * extension - prevents derivation by extension
        /// * restriction - prevents derivation by restriction
        /// * #all - prevents all derivation</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementComplexType(IXsdModel model, string id, string name, bool? @abstract, bool? mixed, string block, string final,
            IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Element || parent == XsdElement.Redefine || parent == XsdElement.Schema)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("complexType can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(name)) {
                AddXsdAttribute(attributes, "name", name);
            }

            if(@abstract.HasValue) {
                AddXsdAttribute(attributes, "abstract", @abstract.Value ? "true" : "false");
            }

            if(mixed.HasValue) {
                AddXsdAttribute(attributes, "mixed", mixed.Value ? "true" : "false");
            }

            if(!string.IsNullOrEmpty(block)) {
                AddXsdAttribute(attributes, "block", block);
            }

            if(!string.IsNullOrEmpty(final)) {
                AddXsdAttribute(attributes, "final", final);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "complexType", attributes);
        }
        #endregion

        #region Documentation
        /// <summary>
        /// Creates element documentation. The documentation element is used to enter text comments in a schema.
        /// This element must go inside an annotation element.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="source">Optional. Specifies the source of the application information.</param>
        /// <param name="lang">Optional. Specifies the language used in the contents.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementDocumentation(IXsdModel model, string source, string lang, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Annotation)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("documentation can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            if(!string.IsNullOrEmpty(source)) {
                AddXsdAttribute(attributes, "source", source);
            }

            if(!string.IsNullOrEmpty(lang)) {
                AddNonXsdAttribute(attributes, "xml", "lang", lang, string.Empty);
            }

            return CreateElement(model, "documentation", attributes);
        }
        #endregion

        #region Element
        /// <summary>
        /// Creates element element. The element element defines an element.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Optional. Specifies a name for the element. This attribute is required if the parent element is the schema element.</param>
        /// <param name="ref">Optional. Refers to the name of another element. The ref attribute can include a namespace prefix.
        /// This attribute cannot be used if the parent element is the schema element</param>
        /// <param name="type">Optional. Specifies either the name of a built-in data type, or the name of a simpleType or complexType element.</param>
        /// <param name="substitutionGroup">Optional. Specifies the name of an element that can be substituted with this element. This attribute cannot be used if the parent element is not the schema element</param>
        /// <param name="default">Optional. Specifies a default value for the element (can only be used if the element's content is a simple type or text only).</param>
        /// <param name="fixed">Optional. Specifies a fixed value for the element (can only be used if the element's content is a simple type or text only).</param>
        /// <param name="form">Optional. Specifies the form for the element. "unqualified" indicates that this attribute is not required to be qualified
        /// with the namespace prefix. "qualified" indicates that this attribute must be qualified with the namespace prefix. The default value is the value
        /// of the elementFormDefault attribute of the schema element. This attribute cannot be used if the parent element is the schema element.</param>
        /// <param name="maxOccurs">Optional. Specifies the maximum number of times this element can occur in the parent element. The value can be
        /// any number &gt;= 0, or if you want to set no limit on the maximum number, use the value "unbounded". Default value is 1. This attribute
        /// cannot be used if the parent element is the schema element.</param>
        /// <param name="minOccurs">Optional. Specifies the minimum number of times this element can occur in the parent element.
        /// The value can be any number &gt;= 0. Default value is 1. This attribute cannot be used if the parent element is the schema element.</param>
        /// <param name="nillable">Optional. Specifies whether an explicit null value can be assigned to the element. True enables an instance of the element
        /// to have the null attribute set to true. The null attribute is defined as part of the XML Schema namespace for instances. Default is false.</param>
        /// <param name="abstract">Optional. Specifies whether the element can be used in an instance document. True indicates that the element cannot appear
        /// in the instance document. Instead, another element whose substitutionGroup attribute contains the qualified name (QName) of this element must
        /// appear in this element's place. Default is false.</param>
        /// <param name="block">Optional. Prevents an element with a specified type of derivation from being used in place of this element. This value can contain #all or a list that is a subset of extension, restriction, or equivClass:
        /// * extension - prevents elements derived by extension
        /// * restriction - prevents elements derived by restriction
        /// * substitution - prevents elements derived by substitution
        /// * #all - prevents all derived elements</param>
        /// <param name="final">Optional. Sets the default value of the final attribute on the element element.  This attribute cannot be used if the parent element is not the schema element. This value can contain #all or a list that is a subset of extension or restriction:
        /// * extension - prevents elements derived by extension
        /// * restriction - prevents elements derived by restriction
        /// * #all - prevents all derived elements</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementElement(IXsdModel model, string id, string name, string @ref, string type, string substitutionGroup, string @default,
            string @fixed, Form? form, string maxOccurs, string minOccurs, bool? nillable, bool? @abstract, string block, string final, IEnumerable<IBigXmlAttribute> additionalAttributes,
            XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Schema || parent == XsdElement.Choice || parent == XsdElement.All || parent == XsdElement.Sequence || parent == XsdElement.Group)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("element can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(name)) {
                AddXsdAttribute(attributes, "name", name);
            }

            if(!string.IsNullOrEmpty(@ref)) {
                AddXsdAttribute(attributes, "ref", @ref);
            }

            if(!string.IsNullOrEmpty(type)) {
                AddXsdAttribute(attributes, "type", type);
            }

            if(!string.IsNullOrEmpty(substitutionGroup)) {
                AddXsdAttribute(attributes, "substitutionGroup", substitutionGroup);
            }

            if(!string.IsNullOrEmpty(@default)) {
                AddXsdAttribute(attributes, "default", @default);
            }

            if(!string.IsNullOrEmpty(@fixed)) {
                AddXsdAttribute(attributes, "fixed", @fixed);
            }

            if(form.HasValue) {
                AddXsdAttribute(attributes, "form", form.Value.ToString().ToLower());
            }

            if(!string.IsNullOrEmpty(maxOccurs)) {
                AddXsdAttribute(attributes, "maxOccurs", maxOccurs);
            }

            if(!string.IsNullOrEmpty(minOccurs)) {
                AddXsdAttribute(attributes, "minOccurs", minOccurs);
            }

            if(nillable.HasValue) {
                AddXsdAttribute(attributes, "nillable", nillable.Value ? "true" : "false");
            }

            if(@abstract.HasValue) {
                AddXsdAttribute(attributes, "abstract", @abstract.Value ? "true" : "false");
            }

            if(!string.IsNullOrEmpty(block)) {
                AddXsdAttribute(attributes, "block", block);
            }

            if(!string.IsNullOrEmpty(final)) {
                AddXsdAttribute(attributes, "final", final);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "element", attributes);
        }
        #endregion

        #region Extension
        /// <summary>
        /// Creates element extension. The extension element extends an existing simpleType or complexType element.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="base">Required. Specifies the name of a built-in data type, a simpleType element, or a complexType element.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementExtension(IXsdModel model, string id, string @base, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.SimpleContent || parent == XsdElement.ComplexContent)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("extension can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);
            if(string.IsNullOrEmpty(@base)) {
                throw new ArgumentNullException("base");
            }

            AddXsdAttribute(attributes, "base", @base);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "extension", attributes);
        }
        #endregion

        #region Field
        /// <summary>
        /// Creates element field. The field element specifies an XPath expression that specifies the value used to define an identity constraint.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="xpath">Required. Identifies a single element or attribute whose content or value is used for the constraint.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementField(IXsdModel model, string id, string xpath, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Key || parent == XsdElement.KeyRef || parent == XsdElement.Unique)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("field can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(xpath)) {
                throw new ArgumentNullException("xpath");
            }

            AddXsdAttribute(attributes, "xpath", xpath);
            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "field", attributes);
        }
        #endregion

        #region Group
        /// <summary>
        /// Creates element group. The group element is used to define a group of elements to be used in complex type definitions.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Optional. Specifies a name for the group. This attribute is used only when the schema
        /// element is the parent of this group element. Name and ref simpleTypes cannot both be present.</param>
        /// <param name="ref">Optional. Refers to the name of another group. Name and ref simpleTypes cannot both be present.</param>
        /// <param name="maxOccurs">Optional. Specifies the maximum number of times the group element can occur in the parent element.
        /// The value can be any number &gt;= 0, or if you want to set no limit on the maximum number, use the value "unbounded". Default value is 1</param>
        /// <param name="minOccurs">Optional. Specifies the minimum number of times the group element can occur in the parent element.
        /// The value can be any number &gt;= 0. Default value is 1.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementGroup(IXsdModel model, string id, string name, string @ref, string maxOccurs, string minOccurs,
            IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Schema || parent == XsdElement.Choice || parent == XsdElement.Sequence || parent == XsdElement.ComplexType
                || parent == XsdElement.Restriction || parent == XsdElement.Extension)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("group can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(name)) {
                AddXsdAttribute(attributes, "name", name);
            }

            if(!string.IsNullOrEmpty(@ref)) {
                AddXsdAttribute(attributes, "ref", @ref);
            }

            ParseMaxOccurs(maxOccurs, attributes);

            ParseMinOccurs(minOccurs, attributes);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "group", attributes);
        }


        #endregion

        #region Import
        /// <summary>
        /// Creates element import. The import element is used to add multiple schemas with different target namespace to a document.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="namespace">Optional. Specifies the URI of the namespace to import.</param>
        /// <param name="schemaLocation">Optional. Specifies the URI to the schema for the imported namespace.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementImport(IXsdModel model, string id, string @namespace, string schemaLocation, IEnumerable<IBigXmlAttribute> additionalAttributes,
            XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Schema)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("import can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(@namespace)) {
                AddXsdAttribute(attributes, "namespace", @namespace);
            }

            if(!string.IsNullOrEmpty(schemaLocation)) {
                AddXsdAttribute(attributes, "schemaLocation", schemaLocation);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "import", attributes);
        }
        #endregion

        #region Include
        /// <summary>
        /// Creates element include. The include element is used to add multiple schemas with the same target namespace to a document.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="schemaLocation">Required. Specifies the URI to the schema to include in the target namespace of the containing schema.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementInclude(IXsdModel model, string id, string schemaLocation, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Schema)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("include can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(schemaLocation)) {
                throw new ArgumentNullException("schemaLocation");
            }

            AddXsdAttribute(attributes, "schemaLocation", schemaLocation);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "include", attributes);
        }
        #endregion

        #region Key
        /// <summary>
        /// Creates element key. The key element specifies an attribute or element value as a key
        /// (unique, non-nullable, and always present) within the containing element in an instance document.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Required. Specifies the name of the key element.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementKey(IXsdModel model, string id, string name, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Element)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("key can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(name)) {
                throw new ArgumentNullException("name");
            }

            AddXsdAttribute(attributes, "name", name);

            AddAdditionalAttributes(attributes, additionalAttributes);
            return CreateElement(model, "key", attributes);
        }
        #endregion

        #region KeyRef
        /// <summary>
        /// Creates element keyRef. The keyref element specifies that an attribute or element value correspond to those of the specified key or unique element.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Required. Specifies the name of the keyref element.</param>
        /// <param name="refer">Required. Specifies the name of a key or unique element defined in this or another schema.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementKeyRef(IXsdModel model, string id, string name, string refer, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Element)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("keyRef can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(name)) {
                throw new ArgumentNullException("name");
            }

            AddXsdAttribute(attributes, "name", name);

            if(string.IsNullOrEmpty(refer)) {
                throw new ArgumentNullException("refer");
            }

            AddXsdAttribute(attributes, "refer", refer);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "keyRef", attributes);
        }
        #endregion

        #region List
        /// <summary>
        /// Creates element list. The list element defines a simple type element as a list of values of a specified data type.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="itemType">Specifies the name of a built-in data type or simpleType
        /// element defined in this or another schema. This attribute is not allowed if the content contains a simpleType element, otherwise it is required.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementList(IXsdModel model, string id, string itemType, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.SimpleType)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("list can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(itemType)) {
                AddXsdAttribute(attributes, "itemType", itemType);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "list", attributes);
        }
        #endregion

        #region Notation
        /// <summary>
        /// Creates element notation. The notation element describes the format of non-XML data within an XML document.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Required. Specifies a name for the element.</param>
        /// <param name="public">Required. Specifies a URI corresponding to the public identifier.</param>
        /// <param name="system">Optional. Specifies a URI corresponding to the system identifier.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementNotation(IXsdModel model, string id, string name, string @public, string system, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Schema)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("notation can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();
            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(name)) {
                throw new ArgumentNullException("name");
            }

            AddXsdAttribute(attributes, "name", name);

            if(string.IsNullOrEmpty(@public)) {
                throw new ArgumentNullException("public");
            }

            AddXsdAttribute(attributes, "public", @public);

            if(!string.IsNullOrEmpty(system)) {
                AddXsdAttribute(attributes, "system", system);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "notation", attributes);
        }
        #endregion

        #region Redefine
        /// <summary>
        /// Creates element redefine. The redefine element redefines simple and complex types, groups, and attribute groups from an external schema.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="schemaLocation">Required. A URI to the location of a schema document.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementRedefine(IXsdModel model, string id, string schemaLocation, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Schema)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("redefine can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(schemaLocation)) {
                throw new ArgumentNullException("schemaLocation");
            }

            AddXsdAttribute(attributes, "schemaLocation", schemaLocation);

            AddAdditionalAttributes(attributes, additionalAttributes);
            return CreateElement(model, "redefine", attributes);
        }
        #endregion

        #region Restriction
        /// <summary>
        /// Creates element restriction. The restriction element defines restrictions on a simpleType, simpleContent, or complexContent definition.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="base">Required. Specifies the name of a built-in data type, simpleType element, or complexType element defined in this schema or another schema.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementRestriction(IXsdModel model, string id, string @base, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.SimpleType || parent == XsdElement.SimpleContent || parent == XsdElement.ComplexContent)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("restriction can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(@base)) {
                throw new ArgumentNullException("base");
            }

            AddXsdAttribute(attributes, "base", @base);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "restriction", attributes);
        }
        #endregion

        #region Schema
        /// <summary>
        /// Creates element schema. The schema element defines the root element of a schema.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="attributeFormDefault">Optional. The form for simpleTypes declared in the target namespace of this schema.
        /// The value must be "qualified" or "unqualified". Default is "unqualified". "unqualified" indicates that simpleTypes from
        /// the target namespace are not required to be qualified with the namespace prefix. "qualified" indicates that simpleTypes
        /// from the target namespace must be qualified with the namespace prefix.</param>
        /// <param name="elementFormDefault">Optional. The form for elements declared in the target namespace of this schema.
        /// The value must be "qualified" or "unqualified". Default is "unqualified". "unqualified" indicates that elements
        /// from the target namespace are not required to be qualified with the namespace prefix. "qualified" indicates that
        /// elements from the target namespace must be qualified with the namespace prefix.</param>
        /// <param name="blockDefault">Optional. Specifies the default value of the block attribute on element and complexType elements
        /// in the target namespace. The block attribute prevents a complex type (or element) that has a specified type of derivation
        /// from being used in place of this complex type. This value can contain #all or a list that is a subset of extension,
        /// restriction, or substitution:
        /// * extension - prevents complex types derived by extension
        /// * restriction - prevents complex types derived by restriction
        /// * substitution - prevents substitution of elements
        /// * #all - prevents all derived complex types.</param>
        /// <param name="finalDefault">Optional. Specifies the default value of the final attribute on element, simpleType,
        /// and complexType elements in the target namespace. The final attribute prevents a specified type of derivation of an element,
        /// simpleType, or complexType element. For element and complexType elements, this value can contain #all or a list that is
        /// a subset of extension or restriction. For simpleType elements, this value can additionally contain list and union:
        /// * extension - prevents derivation by extension
        /// * restriction - prevents derivation by restriction
        /// * list - prevents derivation by list
        /// * union - prevents derivation by union
        /// * #all - prevents all derivation.</param>
        /// <param name="targetNamespace">Optional. A URI reference of the namespace of this schema.</param>
        /// <param name="version">Optional. Specifies the version of the schema.</param>
        /// <param name="xmlns">A URI reference that specifies one or more namespaces for use in this schema. If no prefix is assigned, the schema
        /// components of the namespace can be used with unqualified references.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns></returns>
        public static BigXmlNode CreateElementSchema(IXsdModel model, string id, Form? attributeFormDefault, Form? elementFormDefault,
            string blockDefault, string finalDefault, string targetNamespace, string version, string xmlns, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue) {
                throw new InvalidOperationException("element schema cannot have parent.");
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(attributeFormDefault.HasValue) {
                AddXsdAttribute(attributes, "attributeFormDefault", attributeFormDefault.Value.ToString().ToLower());
            }

            if(elementFormDefault.HasValue) {
                AddXsdAttribute(attributes, "elementFormDefault", elementFormDefault.Value.ToString().ToLower());
            }

            if(!string.IsNullOrEmpty(blockDefault)) {
                AddXsdAttribute(attributes, "blockDefault", blockDefault);
            }

            if(!string.IsNullOrEmpty(finalDefault)) {
                AddXsdAttribute(attributes, "finalDefault", finalDefault);
            }

            if(!string.IsNullOrEmpty(targetNamespace)) {
                AddXsdAttribute(attributes, "targetNamespace", targetNamespace);
            }

            if(!string.IsNullOrEmpty(version)) {
                AddXsdAttribute(attributes, "version", version);
            }

            //if(!string.IsNullOrEmpty(xmlns)) {
            //    AddXsdAttribute(simpleTypes, "xmlns", xmlns);
            //}

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "schema", xmlns, model.XsPrefix, attributes);
        }
        #endregion

        #region Selector
        /// <summary>
        /// Creates element selector. The selector element specifies an XPath expression that
        /// selects a set of elements for an identity constraint (unique, key, and keyref elements).
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="xpath">Required. Specifies an XPath expression, relative to the element being declared,
        /// that identifies the child elements to which the identity constraint applies.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementSelector(IXsdModel model, string id, string xpath, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Key || parent == XsdElement.KeyRef || parent == XsdElement.Unique)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("selector can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(xpath)) {
                throw new ArgumentNullException("xpath");
            }

            AddXsdAttribute(attributes, "xpath", xpath);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "selector", attributes);
        }
        #endregion

        #region Sequence
        /// <summary>
        /// Creates element sequence. The sequence element specifies that the child elements must appear in a sequence. Each child element can occur from 0 to any number of times.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="maxOccurs">Optional. Specifies the maximum number of times the sequence element can occur in the parent element.
        /// The value can be any number &gt;= 0, or if you want to set no limit on the maximum number, use the value "unbounded". Default value is 1.</param>
        /// <param name="minOccurs">Optional. Specifies the minimum number of times the sequence element
        /// can occur in the parent element. The value can be any number &gt;= 0. Default value is 1.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementSequence(IXsdModel model, string id, string maxOccurs, string minOccurs, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Group || parent == XsdElement.Choice || parent == XsdElement.Sequence || parent == XsdElement.ComplexType || parent == XsdElement.Restriction
                || parent == XsdElement.Extension)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("sequence can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            ParseMaxOccurs(maxOccurs, attributes);

            ParseMinOccurs(minOccurs, attributes);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "sequence", attributes);
        }
        #endregion

        #region SimpleContent
        /// <summary>
        /// Creates element simpleContent. The simpleContent element contains extensions or restrictions on a text-only
        /// complex type or on a simple type as content and contains no elements.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementSimpleContent(IXsdModel model, string id, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.ComplexType)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("simpleContent can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);
            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "simpleContent", attributes);
        }
        #endregion

        #region SimpleType
        /// <summary>
        /// Creates element simpleType. The simpleType element defines a simple type and specifies
        /// the constraints and information about the values of simpleTypes or text-only elements.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Specifies a name for the element. This attribute is required if the simpleType
        /// element is a child of the schema element, otherwise it is not allowed.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementSimpleType(IXsdModel model, string id, string name, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Attribute || parent == XsdElement.Element || parent == XsdElement.List || parent == XsdElement.Restriction || parent == XsdElement.Schema
                || parent == XsdElement.Union)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("simpleType can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(name)) {
                AddXsdAttribute(attributes, "name", name);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "simpleType", attributes);
        }
        #endregion

        #region Union
        /// <summary>
        /// Creates element union. The union element defines a simple type as a collection (union) of values from specified simple data types.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="memberTypes">Optional. Specifies a list of built-in data types or simpleType elements defined in a schema.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementUnion(IXsdModel model, string id, string memberTypes, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.SimpleType)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("union can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(!string.IsNullOrEmpty(memberTypes)) {
                AddXsdAttribute(attributes, "memberTypes", memberTypes);
            }

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "union", attributes);
        }
        #endregion

        #region Unique
        /// <summary>
        /// Creates element unique. The unique element defines that an element or an attribute value must be unique within the scope.
        /// The unique element MUST contain the following (in order):
        /// * one and only one selector element  (contains an XPath expression that specifies the set of elements across which the values specified by field must be unique)
        /// * one or more field elements (contains an XPath expression that specifies the values that must be unique for the set of elements specified by the selector element)
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="id">Optional. Specifies a unique ID for the element.</param>
        /// <param name="name">Required. Specifies a name for the element.</param>
        /// <param name="additionalAttributes">Optional. Specifies any other simpleTypes with non-schema namespace.</param>
        /// <param name="parent">Optional parent element.</param>
        /// <returns>Created element.</returns>
        public static BigXmlNode CreateElementUnique(IXsdModel model, string id, string name, IEnumerable<IBigXmlAttribute> additionalAttributes, XsdElement? parent) {
            if(parent.HasValue && (parent == XsdElement.Element)) {
                // parent is ok
            } else if(parent.HasValue) {
                throw new InvalidOperationException(string.Format("selector can't be a child of parent {0}", parent.ToString()));
            }

            var attributes = new List<IBigXmlAttribute>();

            AddIdAttribute(attributes, id);

            if(string.IsNullOrEmpty(name)) {
                throw new ArgumentNullException("name");
            }

            AddXsdAttribute(attributes, "name", name);

            AddAdditionalAttributes(attributes, additionalAttributes);

            return CreateElement(model, "unique", attributes);
        }
        #endregion

        #region Facets
        /// <summary>
        /// Creates specified facet.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="facet">Facet to create.</param>
        /// <param name="value">Value for the facet.</param>
        /// <returns>Created facet.</returns>
        public static BigXmlNode CreateFacet(IXsdModel model, XsdFacet facet, string value) {
            var attributes = new List<IBigXmlAttribute>();

            AddXsdAttribute(attributes, "value", value);

            return CreateElement(model, facet.ToString(), attributes);
        }
        #endregion

        #region Generic
        /// <summary>
        /// Creates element from XMLSchema namespace with xs prefix without any simpleTypes.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="name">Local name of the element to create.</param>
        /// <returns>Reference to newly created element.</returns>
        public static BigXmlNode CreateElement(IXsdModel model, string name) {
            var element = model.CreateElement(model.XsPrefix, name, XsNamespaceUri);
            return element;
        }
        #endregion

        #region Helper
        private static void ParseMinOccurs(string minOccurs, ICollection<IBigXmlAttribute> attributes) {
            if(!string.IsNullOrEmpty(minOccurs)) {
                int min;
                if(int.TryParse(minOccurs, out min) && min >= 0) {
                    AddXsdAttribute(attributes, "minOccurs", minOccurs);
                } else {
                    throw new ArgumentException("minOccurs");
                }
            }
        }

        private static void ParseMaxOccurs(string maxOccurs, ICollection<IBigXmlAttribute> attributes) {
            if(!string.IsNullOrEmpty(maxOccurs)) {
                int max;
                if((int.TryParse(maxOccurs, out max) && max >= 0) || maxOccurs == "unbounded") {
                    AddXsdAttribute(attributes, "maxOccurs", maxOccurs);
                } else {
                    throw new ArgumentException("maxOccurs");
                }
            }
        }

        /// <summary>
        /// Adds xsd attribute to the collection of simpleTypes.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        /// <param name="name">Name of the attribute.</param>
        /// <param name="value">Value of the attribute.</param>
        private static void AddXsdAttribute(ICollection<IBigXmlAttribute> attributes, string name, string value) {
            attributes.Add(new BigXmlAttribute(name, value));
        }

        /// <summary>
        /// Adds non xsd attribute to the collection of simpleTypes.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        /// <param name="prefix">Prefix of the attribute.</param>
        /// <param name="localName">Local name of the attribute.</param>
        /// <param name="value">Value of the attribute.</param>
        /// <param name="namespaceURI">Namespace uri of the attribute.</param>
        private static void AddNonXsdAttribute(ICollection<IBigXmlAttribute> attributes, string prefix, string localName, string value, string namespaceURI) {
            attributes.Add(new BigXmlAttribute(prefix, localName, namespaceURI, value));
        }

        /// <summary>
        /// Adds id attribute to the collection of simpleTypes. If value is empty or null, it is not added.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        /// <param name="value">Value of id attribute.</param>
        private static void AddIdAttribute(ICollection<IBigXmlAttribute> attributes, string value) {
            if(!string.IsNullOrEmpty(value)) {
                AddXsdAttribute(attributes, "id", value);
            }
        }

        /// <summary>
        /// Adds any additional simpleTypes to the collection of simpleTypes.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        /// <param name="additionalAttributes">Additional simpleTypes to add.</param>
        private static void AddAdditionalAttributes(ICollection<IBigXmlAttribute> attributes, IEnumerable<IBigXmlAttribute> additionalAttributes) {
            if(additionalAttributes == null)
                return;
            foreach(var att in additionalAttributes) {
                AddNonXsdAttribute(attributes, att.Prefix, att.LocalName, att.Value, att.NamespaceURI);
            }
        }

        /// <summary>
        /// Creates element from XMLSchema namespace with xs prefix.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="name">Local name of the element to create.</param>
        /// <param name="attributes">The attributes.</param>
        /// <returns>Reference to newly created element.</returns>
        private static BigXmlNode CreateElement(IXsdModel model, string name, IEnumerable<IBigXmlAttribute> attributes) {
            var element = model.CreateElement(model.XsPrefix, name, XsNamespaceUri);

            foreach(var att in attributes) {
                model.AddAttribute(element, att.Prefix, att.LocalName, att.NamespaceURI, att.Value);
            }

            return element;
        }

        /// <summary>
        /// Creates element.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="name">Local name of the element to create.</param>
        /// <param name="namespaceURI">Namespace uri of the element.</param>
        /// <param name="prefix">Prefix for the uri.</param>
        /// <param name="attributes">The attributes.</param>
        /// <returns>Reference to created element.</returns>
        private static BigXmlNode CreateElement(IXsdModel model, string name, string namespaceURI, string prefix, IEnumerable<IBigXmlAttribute> attributes) {
            var element = model.CreateElement(prefix, name, namespaceURI);

            foreach(var att in attributes) {
                model.AddAttribute(element, att.Prefix, att.LocalName, att.NamespaceURI, att.Value);
            }

            return element;
        }
        #endregion
    }
}